﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Java.Util;
using Microsoft.Maui.Graphics.Text;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using MauiAndroidBluetoothTest.Models;
using MauiAndroidBluetoothTest.Services.BluetoothService;
using Xamarin.Google.Crypto.Tink.Subtle;

namespace MauiAndroidBluetoothTest.ViewModels
{
    public sealed partial class MainViewModel : ObservableObject, IDisposable
    {
        private readonly IBluetoothService bluetooth;
        public MainViewModel(IBluetoothService bluetooth)
        {
            this.bluetooth = bluetooth;
        }

        [RelayCommand]
        void RefreshBluetoothState()
        {
            if (!bluetooth.IsEnabled)
            {
                _ = messages.AppendLine($"<*> 蓝牙功能未开启");
                BondedDevices = null;
                return;
            }
            BondedDevices = bluetooth.GetBondedDevices().ToImmutableList();
            _ = messages.AppendLine($"<*> 刷新成功");
        }

        [ObservableProperty]
        IReadOnlyList<IBluetoothDeviceInfo> bondedDevices;

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(AvailableUuids))]
        IBluetoothDeviceInfo selectedDevice;

        public IReadOnlyList<UUID> AvailableUuids => SelectedDevice?.Uuids?.ToImmutableList();

        [ObservableProperty]
        UUID selectedUuid;

        private CancellationTokenSource connectionReadTaskCancellationTokenSource;

        private async Task StartRead(int bufferSize, CancellationToken token)
        {
            var buffer = new byte[bufferSize];
            for (; ; )
            {
                try
                {
                    var count = await Connection.InputStream.ReadAsync(buffer, token);
                    if (token.IsCancellationRequested)
                        return;

                    _ = Messages.AppendLine($"--> {string.Join(' ', buffer.Take(count))}");
                }
                catch (Exception ex)
                {
                    if (token.IsCancellationRequested)
                        return;
                    _ = messages.AppendLine($"<*> 接收时遇到错误：{ex.Message}");
                }
            }
        }

        [RelayCommand]
        async Task ConnectDeviceAsync()
        {
            DisconnectDevice();
            try
            {
                var connection = bluetooth.CreateConnection(selectedDevice?.Address, selectedUuid);
                await connection.ConnectAsync();
                Connection = connection;
                var device = connection.Device;

                connectionReadTaskCancellationTokenSource = new();
                _ = StartRead(bufferSize: 1024,
                    connectionReadTaskCancellationTokenSource.Token);

                _ = messages.AppendLine($"<*> 已连接到 {device.Name} {device.Address}");
            }
            catch(Exception ex)
            {
                _ = messages.AppendLine($"<*> 连接失败：{ex.Message}");
            }
        }

        [ObservableProperty]
        BluetoothConnection connection;

        [RelayCommand]
        void DisconnectDevice()
        {
            if(Connection is not null)
            {
                Debug.Assert(connectionReadTaskCancellationTokenSource is not null);
                connectionReadTaskCancellationTokenSource.Cancel();
                connectionReadTaskCancellationTokenSource.Dispose();

                var device = Connection.Device;
                Connection.Dispose();
                Connection = null;
                _ = messages.AppendLine($"<*> 已断开与 {device.Alias} {device.Address} 的连接");
            }
        }

        [ObservableProperty]
        AppendableString messages = new(limit: 32767);

        [ObservableProperty]
        string messageToSend;

        [RelayCommand]
        async Task SendDecimalsAsync()
        {
            try
            {
                var decimals = messageToSend.Split().Select(s => byte.Parse(s)).ToArray();
                await Connection.OutputStream.WriteAsync(decimals);
                _ = messages.AppendLine($"<-- {string.Join(' ', decimals)}");
            }
            catch (Exception ex)
            {
                _ = messages.AppendLine($"<*> 发送时遇到错误：{ex.Message}");
            }
        }

        public void Dispose()
        {
            connection?.Dispose();
            connectionReadTaskCancellationTokenSource?.Dispose();
        }
    }
}
